package com.system.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.system.demo.commonService.RedisService;
import com.system.demo.entity.DTO.NewStudentDTO;
import com.system.demo.entity.DTO.StudentIdsRequest;
import com.system.demo.entity.VO.QueryUsersVO;
import com.system.demo.entity.auth.DTO.RoleIdsDTO;
import com.system.demo.entity.auth.SystemRole;
import com.system.demo.entity.database.*;
import com.system.demo.entity.auth.UserRole;
import com.system.demo.mapper.*;
import com.system.demo.mapper.auth.SystemRoleMapper;
import com.system.demo.service.UserService;
import com.system.demo.tool.ResponseResult;
import com.system.demo.utils.ExcelExportUtil;
import com.system.demo.utils.MinioUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.system.demo.service.constant.RoleConstant.*;
import static com.system.demo.service.constant.UserConstant.PREFIX_OF_DEFAULT_PASSWORD;
import static com.system.demo.service.constant.UserConstant.TEMPLATE_EXCEL_FILE;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private MinioUtils minioUtils;

    @Autowired
    private SystemRoleMapper systemRoleMapper;

    @Autowired
    private SubmitApplicationMapper submitApplicationMapper;

    @Autowired
    private CompetitionFileMapper competitionFileMapper;

    @Autowired
    private CognizanceMapper cognizanceMapper;

    @Autowired
    private PaperSubmitMapper paperSubmitMapper;

    @Autowired
    private LeaveMapper leaveMapper;

    @Value("${minio.bucketName}")
    private String bucketName;
    @Override
    @Transactional
    public ResponseResult<?> addNewUserByOnce(NewStudentDTO studentDTO) {
        // 定义 Redis 锁的 Key，使用学生的唯一标识作为锁的粒度
        String lockKey = "lock:addNewUser:" + studentDTO.getUid();
        long lockExpireTime = 10; // 锁的过期时间（秒）

        // 尝试加锁并执行业务逻辑
        return redisService.executeWithLock(lockKey, lockExpireTime, () -> {

            // 调用内部添加方法
            String s = addNewUserByOnceInternal(studentDTO);
            if (s == null) {
                return ResponseResult.success("添加成功");
            }
            return ResponseResult.Unauthorized("创建学号为：" + s + " 的新用户失败，原因：学生已存在");
        });
    }


    @Override
    @Transactional
    public ResponseResult<?> batchAddStudents(MultipartFile file) {
        List<String> unSuccessStudentsId = new ArrayList<>(); // 初始化未成功处理的学生ID列表
        try {
            List<NewStudentDTO> students = ExcelExportUtil.readExcel(file.getInputStream());

            for (NewStudentDTO student : students) {
                String result = addNewUserByOnceInternal(student); // 调用内部事务方法
                if (result != null) {
                    unSuccessStudentsId.add(result); // 如果返回值不为null，说明处理失败，记录学生ID
                }
            }

            // 根据处理结果返回
            if (unSuccessStudentsId.isEmpty()) {
                return ResponseResult.success("批量添加成功");
            } else {
                return ResponseResult.success("部分学生添加失败", unSuccessStudentsId);
                // 可根据实际需求返回失败列表
            }
        } catch (Exception e) {
            return ResponseResult.InternalServerError("服务器内部错误，处理Excel文件出错：" + e.getMessage());
        }
    }

    @Override
    @Transactional
    public ResponseResult<?> deleteStudents(StudentIdsRequest studentIds) {
        try {
            List<String> uids = studentIds.getStudentIds();

            // 删除 competition_file 和 cognizance 中的记录
            List<Integer> applicationIds = submitApplicationMapper.selectIdsByUids(uids);
            if (applicationIds != null && !applicationIds.isEmpty()) {
                competitionFileMapper.delete(new QueryWrapper<CompetitionFile>()
                        .in("application_id", applicationIds));
                cognizanceMapper.delete(new QueryWrapper<Cognizance>()
                        .in("application_id", applicationIds));
            }
            //删除submitApplication表中的记录
            submitApplicationMapper.delete(new QueryWrapper<SubmitApplication>()
                    .in("uid",uids));

            //删除论文记录
            paperSubmitMapper.delete(new QueryWrapper<Paper>()
                    .in("uid", uids));

            //删除请假记录
            leaveMapper.delete(new QueryWrapper<Leave>()
                    .in("uid",uids));

            // 删除学生表中的记录
            studentMapper.delete(new QueryWrapper<Student>()
                    .in("uid", uids));

            // 删除用户表中的记录
            userMapper.delete(new QueryWrapper<User>()
                    .in("uid", uids));
            //删除user_role表中的记录
            userRoleMapper.delete(new QueryWrapper<UserRole>()
                    .in("uid", uids));

            // 删除 MinIO 中对应学号的文件夹
            for (String studentId : uids) {
                boolean minioDeleteSuccess = minioUtils.deleteFolder(bucketName, studentId);
                if (!minioDeleteSuccess) {
                    throw new RuntimeException("删除 MinIO 文件夹失败：" + studentId);
                }
            }

            return ResponseResult.success("删除成功");
        } catch (Exception e) {
            return ResponseResult.InternalServerError("删除过程中发生错误：" + e.getMessage());
        }
    }

    public ResponseEntity<InputStreamResource> getExcelTemplate() {
        try {

            // 下载文件
            InputStreamResource fileResource = minioUtils.downloadFile(bucketName, TEMPLATE_EXCEL_FILE);

            if (fileResource == null) {
                return ResponseEntity.notFound().build();
            }

            // 设置响应头，让浏览器知道这是一个需要下载的文件
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=天工创新学院系统导入学生用户模板.xlsx");

            // 返回ResponseEntity对象
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(fileResource);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    @Override
    public ResponseResult<?> getUsersByLimits(String role, String uid, String stuClass, String name,  String current, String size) {
        IPage<QueryUsersVO> page = new Page<>(Long.parseLong(current), Long.parseLong(size));
        IPage<QueryUsersVO> usersPage;
        try {
            usersPage  = userMapper.getUsersByLimitsPage(page ,role, uid, stuClass, name);

        } catch (Exception e){
            System.out.println(e.getMessage());
            return ResponseResult.InternalServerError("查询失败" + e.getMessage());
        }
        // 返回分页结果
        return ResponseResult.success("筛选成功", usersPage.getTotal(), usersPage.getRecords());

    }


    @Override
    public ResponseResult<?> resetUser(String uid) {
        //重置用户 也就是当用户密码忘记了 邮箱也无法找回了  管理员可以重置该用户密码 也就是最原始的"TIS@学号"
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUid, uid);

        User user = userMapper.selectOne(wrapper);
        if(user == null){
            return ResponseResult.NotFound("未查找到用户信息，请联系管理员");
        }
        user.setPassword(DigestUtils.md5DigestAsHex((PREFIX_OF_DEFAULT_PASSWORD+uid).getBytes()));
        user.setMail(null);
        if(!(userMapper.updateById(user) > 0)){
            return ResponseResult.InternalServerError("服务器内部错误，请重试");
        }
        return ResponseResult.success("重置密码成功");
    }


    private Boolean isUserExists(String uid) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUid, uid);

        User user = userMapper.selectOne(wrapper);
        return user != null;
    }

    @Override
    public ResponseResult<?> getRoleListForUid(String uid) {
        List<Integer> roleIdsByUserId = userMapper.getRoleIdsByUserId(uid);

        return ResponseResult.success("该用户的角色集合查找成功",roleIdsByUserId.size(), roleIdsByUserId);
    }

    @Override
    @Transactional
    public ResponseResult<?> reviseRoleForUser(String uid, RoleIdsDTO roleIdsDTO) {
        // 获取当前用户已有的角色ID列表（确保返回的是Integer类型）
        List<Integer> currentRoleIds = userRoleMapper.findRoleIdsByUid(uid);
        Set<Integer> currentRolesSet = new HashSet<>(currentRoleIds);

        // 获取新提供的角色ID列表，并去除重复项
        Set<Integer> newRolesSet = new HashSet<>(roleIdsDTO.getRoleIds());

        // 确定需要添加的角色和需要移除的角色
        Set<Integer> rolesToAdd = new HashSet<>(newRolesSet);
        rolesToAdd.removeAll(currentRolesSet); // 需要添加的新角色

        Set<Integer> rolesToRemove = new HashSet<>(currentRolesSet);
        rolesToRemove.removeAll(newRolesSet); // 需要去除的旧角色

        // 不能移除系统默认角色 (例如学生身份)
        if (rolesToRemove.contains(ROLE_STUDENT)) {
            return ResponseResult.Unauthorized("无法删除系统默认角色！");
        }

        if(rolesToAdd.contains(ROLE_ADMIN)){
            return ResponseResult.Unauthorized("系统管理员 不能被赋予");
        }

        if (rolesToAdd.contains(ROLE_STUDENT)) {
            return ResponseResult.Unauthorized("学生 该角色是系统默认角色 无需赋予");
        }
        // 添加新角色
        for (Integer roleId : rolesToAdd) {
            LambdaQueryWrapper<SystemRole> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SystemRole::getRoleId, roleId);
            SystemRole systemRole = systemRoleMapper.selectOne(queryWrapper);
            if(systemRole == null){
                return ResponseResult.BadRequest("系统无该角色");
            }

            UserRole userRole = new UserRole();
            userRole.setRoleId(roleId);
            userRole.setUid(uid);
            userRole.setIsAvailable(ROLE_IS_AVAILABLE);
            userRole.setCreateTime(LocalDateTime.now());
            if(!(userRoleMapper.insert(userRole) > 0)){
                return ResponseResult.InternalServerError("服务器内部错误，请重试");
            }
        }

        // 移除旧角色
        for (Integer roleId : rolesToRemove) {
            LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserRole::getUid, uid)
                    .eq(UserRole::getRoleId, roleId);

            int rowsAffected = userRoleMapper.delete(wrapper);
            if (rowsAffected <= 0) {
                return ResponseResult.InternalServerError("角色删除失败");
            }
        }

        // 更新用户的菜单权限缓存
        List<String> menuValuesByUid = userMapper.getMenuValuesByUid(uid);
        String key = "menu:" + uid;
        redisService.setTokenKey(key, menuValuesByUid, 15, TimeUnit.DAYS);

        return ResponseResult.success("用户角色更新成功");
    }


    @Transactional
    public String addNewUserByOnceInternal(NewStudentDTO studentDTO) {
        try {
            // 检查用户是否已存在
            if (!isUserExists(studentDTO.getUid())) {
                // 为 student 添加 user，返回 userId 后再添加 student
                User user = new User();
                String id = studentDTO.getId();
                id = id.substring(id.length() - 6); // 获取身份证后六位
                String password = PREFIX_OF_DEFAULT_PASSWORD + id; // 设置默认密码格式

                user.setUid(studentDTO.getUid());
                user.setPassword(DigestUtils.md5DigestAsHex(password.getBytes()));
                user.setUsername(studentDTO.getUid());
                user.setUsername(studentDTO.getStuName());
                if(studentDTO.getGender().equals("男")){
                    user.setAvatar(DEFAULT_BOY_AVATAR);
                }else{
                    user.setAvatar(DEFAULT_GIRL_AVATAR);
                }


                // 设置用户角色学生
                UserRole userRole = new UserRole();
                userRole.setRoleId(ROLE_STUDENT);
                userRole.setUid(studentDTO.getUid());
                userRole.setIsAvailable(ROLE_IS_AVAILABLE);
                userRole.setCreateTime(LocalDateTime.now());

                // 插入 user_role
                if (!(userRoleMapper.insert(userRole) > 0)) {
                    throw new RuntimeException("设置新用户角色时出错，请重试");
                }

                // 插入 user
                if (!(userMapper.insert(user) > 0)) {
                    throw new RuntimeException("添加用户失败");
                }

                // 插入 student
                Student student = new Student();
                student.setUid(studentDTO.getUid());
                student.setStudentClass(studentDTO.getStuClass());
                student.setStudentName(studentDTO.getStuName());
                student.setUserId(user.getId());
                student.setStudentGender(studentDTO.getGender());
                if (!(studentMapper.insert(student) > 0)) {
                    throw new RuntimeException("添加学生失败");
                }
            } else {
                return studentDTO.getUid(); // 如果用户已存在，返回学生ID
            }
        } catch (Exception e) {
            return studentDTO.getUid(); // 如果处理过程中出错，返回学生ID
        }
        return null; // 处理成功返回null
    }
}
